package org.dbwebx.flex.delegate
{

	import com.developmentarc.core.datastructures.utils.HashTable;

	import mx.rpc.AsyncToken;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.mxml.Operation;
	import mx.rpc.remoting.mxml.RemoteObject;

	import org.as3commons.logging.ILogger;
	import org.as3commons.logging.LoggerFactory;
	import org.swizframework.Swiz;

	/**
	 * Implements base logic for <code>RemoteObject</code> method invocations.
	 * @author Izzet_Mustafayev
	 *
	 */
	public class AbstractRemotingDelegate
	{

		/**
		 * The logger.
		 */
		private static var logger:ILogger=LoggerFactory.getClassLogger(AbstractRemotingDelegate);

		public function AbstractRemotingDelegate()
		{
			super();
			cache=new HashTable()
		}

		/**
		 * Contains loaded data to faster access.
		 * @default
		 */
		protected var cache:HashTable;

		/**
		 * Indicates whether data was changed.
		 * @default true
		 */
		protected var _dataChanged:Boolean=true;

		/**
		 * The token.
		 */
		private var token:AsyncToken;

		/**
		 * Invokes destination method.
		 * @param remoteObject the remote object to invoke method of
		 * @param method the method to invoke
		 * @param args the remote destination arguments
		 * @return reference to <code>AsyncToken</code>
		 */
		protected function executeCall(remoteObject:RemoteObject, method:String, args:Array=null):AsyncToken
		{
			var message:String=remoteObject.destination + "." + method + "(" + (args != null ? args.toString() : "") + ")";
			logger.debug("EXECUTE CALL: {0}", message);
			var operation:Operation=remoteObject.getOperation(method) as Operation;
			if (null != operation && null != args)
			{
				token=(operation.send as Function).apply(this, args);
			}
			if (null != operation && null == args)
			{
				token=(operation.send as Function).apply(this);
			}

			return token;
		}

		/**
		 * Executes local call retrieving data from cache.
		 * @param operation the operation to load data
		 * @param resultHandler the result handler for specified operation
		 * @param eventArgs the event arguments to pass next
		 */
		protected function executeLocalCall(operation:String, resultHandler:Function, eventArgs:Array=null):void
		{
			if (logger.debugEnabled)
				logger.debug("Loading data from local cache for operation: {0}", operation);
			var data:*=cache.getItem(operation);
			var resultEvent:ResultEvent=new ResultEvent(ResultEvent.RESULT, false, true, data);
			if (!eventArgs)
			{
				resultHandler(resultEvent);
				;
			}
			else
			{
				eventArgs.unshift(resultEvent);
				resultHandler.apply(null, eventArgs);
			}
		}

		protected function executeServiceCall(call:AsyncToken, resultHandler:Function, faultHandler:Function=null, eventArgs:Array=null):void
		{
			Swiz.executeServiceCall(call, resultHandler, faultHandler, eventArgs);
		}

		protected function isRemoteCallRequired(operation:String):Boolean
		{
			return _dataChanged && operation && !cache.containsKey(operation);
		}

		protected function resolveOperation(methodName:String, ... args:Array):String
		{
			return methodName;
		}

		protected function doCache(key:String, value:*):void
		{
			cache.addItem(key, value);
		}

		/**
		 * Mark that current service data was changed.
		 * @param operation the operation to clear cache of
		 * @param args additinoal operations to clear cache of
		 */
		protected function dataChanged(operation:String, ... args:Array):void
		{
			_dataChanged=true;
			cache.remove(operation);
			if (args)
			{
				var operationsLen:int=args.length;
				for (var i:int=0; i < operationsLen; i++)
				{
					cache.remove(args[i]);
				}
			}
		}
		
		protected function clearAllCache():void
		{
			cache.removeAll();
		}

	}
}